#!/usr/bin/env php
<?php
$SOAR_DIR=getenv("SOAR_DIR");
if(empty($SOAR_DIR)) $SOAR_DIR="/opt/soar";
include_once "$SOAR_DIR/common/php/soar/soar.inc";

function load_cnfg()
{/*{{{*/
    $svcenv_dir=getenv("SVCENV_DIR");
    if(empty($svcenv_dir))
    {
        print "Error: SVCENV_DIR not set\n";
        return false;
    }
    $svcenv_cnfg=getenv("SVCENV_CNFG");
    if(empty($svcenv_cnfg))
    {
        print "Error: SVCENV_CNFG not set\n";
        return false;
    }
    include $svcenv_cnfg;

    return true;
}/*}}}*/

class worker
{/*{{{*/
    public static $worker_idx=9999;

    private static $svcnode=array();

    public function get_svcnode($snname)
    {/*{{{*/
        if(!isset(self::$svcnode[$snname]))
        {
            printf("Error: svcnode(%s) not in cnfg\n", $snname);
            return false;
        }
        return self::$svcnode[$snname];
    }/*}}}*/

    private static $dbconn=array();

    public function get_dbconn($dbname)
    {/*{{{*/
        if(!isset(cnfg::$db[$dbname]))
        {
            printf("Error: db(%s) not in cnfg\n", $dbname);
            return false;
        }
        if(isset(self::$dbconn[$dbname]))
            return self::$dbconn[$dbname];

        $dbcnfg=cnfg::$db[$dbname];
        if(empty($dbcnfg['passwd']))
        {
            if(!isset(cnfg::$svcnode) || !isset(cnfg::$svcnode['passwd']))
            {
                printf("Error: no sn_passwd available\n");
                return false;
            }
            $passwd=svcnode_call::getdbpasswd(
                    cnfg::$svcnode['passwd']['addr'],
                    $dbname, $dbcnfg['user']);
            if($passwd === false)
            {
                printf("Error: get db(%s) passwd fail\n", $dbname);
                return false;
            }
        }
        else
        {
            $passwd=$dbcnfg['passwd'];
        }

        switch($dbcnfg['type'])
        {/*{{{*/
            case "mysql":
            {
                $conn=mysqli_init();
                $conn->options(MYSQLI_INIT_COMMAND, "set names utf8");
                if($conn->real_connect($dbcnfg['host'], $dbcnfg['user'],
                            $passwd, $dbcnfg['database'], 0, null,
                             MYSQLI_CLIENT_FOUND_ROWS) == false)
                {
                    printf("Error: connect to db(%s) fail:%s\n",
                            $dbname, mysqli_connect_errno());
                    return false;
                }
                self::$dbconn[$dbname]=$conn;
                printf("connect db(%s)\n", $dbname);
                break;
            }
            case "oci8":
            {
                $conn=oci_connect($dbcnfg['user'], $passwd,
                        isset($dbcnfg['host'])?
                        $dbcnfg['host']:'localhost');
                if($conn === false)
                {
                    $error=oci_error();
                    printf("Error: connect to db(%s) fail:%d %s",
                            $dbname,
                            $error['code'], $error['message']);
                    return false;
                }
                self::$dbconn[$dbname]=$conn;
                printf("connect to db(%s)\n", $dbname);
                break;
            }
            case "mssql":
            {
                $conn=mssql_connect($dbcnfg['host'], $dbcnfg['user'],
                        $passwd);
                if($conn === false)
                {
                    printf("Error: connect to db(%s) fail",
                            $dbname);
                    return false;
                }
                if(mssql_select_db($dbcnfg['database'], $conn) == false)
                {
                    printf("Error: select db(%s) fail",
                            $dbcnfg['database']);
                    return false;
                }
                self::$dbconn[$dbname]=$conn;
                printf("connect to db(%s)\n", $dbname);
                break;
            }
            default:
            {
                printf("Error: dababase not supported\n");
                $conn=false;
                break;
            }
        }/*}}}*/

        return $conn;
    }/*}}}*/

    private function close_dbconn()
    {/*{{{*/
        foreach(self::$dbconn as $name=>$conn)
        {
            $dbcnfg=cnfg::$db[$name];
            switch($dbcnfg['type'])
            {
                case 'mysql':
                {
                    $conn->close();
                    break;
                }
                case 'oci8':
                {
                    oci_close($conn);
                    break;
                }
                case 'mssql':
                {
                    mssql_close($conn);
                    break;
                }
            }
            unset(self::$dbconn[$name]);
            printf("close db(%s)\n", $name);
        }
    }/*}}}*/

    private static $memcache=array();

    public function get_memcache($mcname)
    {/*{{{*/
        if(!isset(cnfg::$memcache[$mcname]))
        {
            errlog::add("%s: memcache(%s) not in cnfg",
                    __METHOD__, $mcname);
            return false;
        }
        if(isset(self::$memcache[$mcname]))
        {
            $conn=self::$memcache[$mcname];
            if($conn->getVersion())
                return self::$memcache[$mcname];
            $conn->close();
            unset(self::$memcache[$mcname]);
            printf("memcache(%s) down, reconnect", $mcname);
        }

        $mccnfg=cnfg::$memcache[$mcname];
        $arr=split(':', $mccnfg['addr']);
        $conn=new Memcache();
        if($conn->connect($arr[0], $arr[1]) == false)
        {
            errlog::add("%s: connect memcache(%s) fail",
                    __METHOD__, $mcname);
            return false;
        }
        self::$memcache[$mcname]=$conn;

        return $conn;
    }/*}}}*/

    private function close_memcache()
    {/*{{{*/
        foreach(self::$memcache as $name=>$conn)
        {
            $conn->close();
            unset(self::$memcache[$name]);
            printf("close memcache(%s)\n", $name);
        }
    }/*}}}*/

    public function start($isfile, $svc, $request)
    {/*{{{*/
        print "Request:\n";
        print "$svc\n";
        print_r($request);
        print "----------------------------------------\n";

        print "Process:\n";
        if($isfile)
        {
            if(isset(cnfg::$svcnode))
            {
                foreach(cnfg::$svcnode as $snname=>$sncnfg)
                {
                    self::$svcnode[$snname]=new svcnode($sncnfg['addr'],
                            isset($sncnfg['mode'])?
                            $sncnfg['mode'] : svcnode::ONESHOT);
                }
            }
            include_once getenv("SVCENV_DIR")."/src/svc/svr.inc";
            include_once getenv("SVCENV_DIR")."/src/svc/${svc}.inc";
            if(class_exists($svc))
            {
                $ins=new $svc();
                $response=$ins->call($request);
                if($response === false)
                {
                    $response=array('errcode'=>SOAR_ERR::DB);
                }
            }
            else
            {
                printf("svc(%s) not found\n", $svc);
                $response=array('errcode'=>SOAR_ERR::SVC_NOT_FOUND);
            }
            self::close_dbconn();
            self::close_memcache();
        }
        else
        {
            $site=array('addr'=>"localhost:".cnfg::$agent['server_port'],
                    'json'=>true);
            $svcenv=new svcenv($site);
            $response=$svcenv->call($svc, $request);
            if($response === false)
            {
                echo "call svcenv fail\n";
                $svcenv->close();
                return false;
            }
            $svcenv->close();
        }
        print "----------------------------------------\n";
  
        print "Response:\n";
        print_r($response);
        print "----------------------------------------\n";

        return true;
    }/*}}}*/
}/*}}}*/

function usage($selfname)
{/*{{{*/
    print "Usage: $selfname [-f] SERVICE [key:value ...]\n";
    print "Option -f: call service from src/svc directly, not from running SERVER\n";
    print "\n";
}/*}}}*/

function main($argv)
{/*{{{*/
    $selfname=basename(array_shift($argv));
    if(empty($argv))
    {
        usage($selfname);
        return 1;
    }

    $svc=array_shift($argv);
    if($svc == '-f')
    {
        if(empty($argv))
        {
            usage($selfname);
            return 1;
        }
        $svc=array_shift($argv);
        $isfile=true;
    }
    else
        $isfile=false;
    $svc=strtoupper($svc);

    $request=array();
    foreach($argv as $v)
    {
        $arr=split(':', $v);
        if($arr === false || count($arr) != 2)
        {
            print "para($v) invalid\n\n";
            usage($selfname);
            return 1;
        }
        $request[$arr[0]]=$arr[1];
    }

    if(load_cnfg() == false)
        return 1;
    if(worker::start($isfile, $svc, $request) == false)
        return 1;
    return 0;
}/*}}}*/

exit(main($argv));
?>
